package com.lagou.edu.utils;

import com.alibaba.druid.util.StringUtils;
import com.lagou.edu.anno.*;
import com.lagou.edu.factory.BeanFactory;
import com.lagou.edu.factory.ProxyFactory;
import net.sf.cglib.core.CollectionUtils;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public class ParseAnno {

    public static void parse(String parsePath,Map<String,Object> allMap) {
        Set<String> className = getClassName(parsePath, true);
        Map<String,Object> map = new HashMap<>();  // 存储对象
       if (className.size()>0){
           for (String path : className) {
               // 通过反射技术实例化对象
               try {
                   Class<?> aClass = Class.forName(path);
                   if(aClass.isAnnotationPresent(Service.class) ||aClass.isAnnotationPresent(Repository.class)){
                        //通过class获取key
                       String key = getKey(aClass);
                       Object object = aClass.newInstance();

                       //若map原本就有了key，说明key重复，抛出异常
                       if (map.containsKey(key)){
                           throw new RuntimeException("beanId重复异常");
                       }
                       map.put(key,object);

                       Class<?> superclass = aClass.getSuperclass();
                       if (null != superclass && !(superclass instanceof Object)){
                           String superKey = getSuperKey(superclass);
                           map.put(superKey,object);
                       }
                       Class<?>[] interfaces = aClass.getInterfaces();
                       if (interfaces.length>0){
                           for (int i = 0; i < interfaces.length; i++) {
                               String interfacesKey = getSuperKey(interfaces[i]);
                               map.put(interfacesKey,object);
                           }
                       }

                   }
               } catch (NoClassDefFoundError e) {
                   System.out.println(e);
               }catch (ClassNotFoundException e) {
                   System.out.println(e);
               } catch (IllegalAccessException e) {
                   e.printStackTrace();
               } catch (InstantiationException e) {
                   e.printStackTrace();
               }
           }
       }
        System.out.println(map);
        if (map.size()>0){
            map.forEach((k,v)->{
                Class<?> aClass = v.getClass();
                settingFileds(map,  aClass,k);
            });

        }
        allMap.putAll(map);
    }

    private static void settingFileds(Map<String, Object> map, Class<?> aClass,String k) {
        Field[] declaredFields = aClass.getDeclaredFields();
        Object o1 = null;
        try {
            o1 = aClass.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        if (aClass.getDeclaredFields().length>0){
            for (int i = 0; i < declaredFields.length; i++) {
                Field declaredField = declaredFields[i];
                if (declaredField.isAnnotationPresent(Autowired.class)){
                    Class<?> field = declaredField.getType();

                    String key = getKey(field);
                    settingFileds(map,  map.get(key).getClass(),key);

                    if (!map.containsKey(key)){
                        throw new RuntimeException("不存在的bean:"+key);
                    }
                    declaredField.setAccessible(true);
                    try {
                        Object o = map.get(key);
                        declaredField.set(o1, o);
                        map.put(k,o1);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    /**
     * 通过class获取key
     * @param aClass
     * @return
     */
    private static String getKey(Class<?> aClass) {

        Service service = aClass.getAnnotation(Service.class);
        Repository repository = aClass.getAnnotation(Repository.class);
        String key = null == service? (null == repository ? null : repository.value()) : service.value();

        if (StringUtils.isEmpty(key)){
            key = lowerFirstChar(aClass.getSimpleName());
        }
        return key;
    }
    /**
     * 通过父类/接口获取key
     * @param aClass
     * @return
     */
    private static String getSuperKey(Class<?> aClass) {
        return lowerFirstChar(aClass.getSimpleName());
    }

    /**
     * 将类名首字母小写
     * @param str
     * @return
     */
    private static String lowerFirstChar(String str){
        char [] chars = str.toCharArray();
        chars[0] += 32;
        return String.valueOf(chars);
    }

    /**
     * 获取某包下所有类
     *
     * @param packageName 包名
     * @param isRecursion 是否遍历子包
     * @return 类的完整名称
     */
    public static Set<String> getClassName(String packageName, boolean isRecursion) {
        Set<String> classNames = null;
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        String packagePath = packageName.replace(".", "/");

        URL url = loader.getResource(packagePath);
        if (url != null) {
            String protocol = url.getProtocol();
            if (protocol.equals("file")) {
                classNames = getClassNameFromDir(url.getPath(), packageName, isRecursion);
            }
        }
        return classNames;
    }

    /**
     * 从项目文件获取某包下有类
     *
     * @param filePath    文件路径
     * @param isRecursion 是否遍历子包
     * @return 类的完整名称
     */
    private static Set<String> getClassNameFromDir(String filePath, String packageName, boolean isRecursion) {
        Set<String> className = new HashSet<>();
        File file = new File(filePath);
        File[] files = file.listFiles();
        for (File childFile : files) {

            if (childFile.isDirectory()) {
                if (isRecursion) {
                    className.addAll(getClassNameFromDir(childFile.getPath(), packageName + "." + childFile.getName(), isRecursion));
                }
            } else {
                String fileName = childFile.getName();
                //endsWith() 方法用于测试字符串是否以指定的后�?结束�?  !fileName.contains("$") 文件名中不包? '$'
                if (fileName.endsWith(".class") && !fileName.contains("$")) {
                    className.add(packageName + "." + fileName.replace(".class", ""));
                }
            }
        }

        return className;
    }




}
